#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Purpose: Join networks GUI
# Created: 13/09/2010
# Authors:
# Alexandros Ntousias <antousias@gmail.com>, Alexandru Matei <lexan123@gmail.com>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with HydroPlatform for details.

import os
import wx
import wx.grid as gridlib

from hydroplatform.model import database as db
from hydroplatform.model.network import Network
from hydroplatform.model.network import NodeType, LinkType, Node, Link, \
     LinkValue, NodeValue, Network, NodeField

class JoinFrame(wx.Frame):
	'''
	This frame asks the user to select the network which 
	will be joined with the currently active one.
	'''
	def __init__(self, parent, context):
		wx.Frame.__init__(self, parent, -1, u"Network Join")
		self.context = context
		self.project = context.session.hpproject
		self.activeNetwork = self.context.session.hpnetwork.name
		
		self.networkNames = []
		self.networks = []
		self.selectedNetwork = None
		
		for network in self.project.networks:
			if network.name != self.activeNetwork:
				self.networkNames.append(network.name)
				self.networks.append(network)
		
		self.doLayout()
		self.bindEvents()
		self.Centre()
		self.Show()
		
	def doLayout(self):
		panel = wx.Panel(self)
		questionText = wx.StaticText(panel, -1, u"Which network would you like to join to " + self.activeNetwork + " :")
		self.networksCombo = wx.ComboBox(panel, -1, choices=self.networkNames, style=wx.CB_READONLY)
		if self.networkNames.__len__() > 0:
			self.networksCombo.SetValue(self.networkNames[0])
			self.selectedNetwork = self.networks[0]

		self.selectButton = wx.Button(panel, -1, u"Join")
		self.checkSelectButton()
		self.cancelButton = wx.Button(panel, -1, u"Cancel")
		
		# Create the main canvas
		mainSizer = wx.BoxSizer(wx.VERTICAL)
		
		# Create the fields' canvas
		fieldSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
		fieldSizer.AddGrowableCol(1)
		fieldSizer.Add(questionText, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
		fieldSizer.Add(self.networksCombo, 0, wx.EXPAND)
		
		# Add the fields' canvas to the main one
		mainSizer.Add(fieldSizer, 0, wx.EXPAND | wx.ALL, 10)
		
		# Create the button canvas
		btnSizer = wx.BoxSizer(wx.HORIZONTAL)
		btnSizer.Add((20,20), 1)
		btnSizer.Add(self.selectButton)
		btnSizer.Add((20,20),1)
		btnSizer.Add(self.cancelButton)
		btnSizer.Add((20,20),1)
		
		# Add button canvas to the main one
		mainSizer.Add(btnSizer, 0, wx.EXPAND | wx.ALL, 10)
		
		panel.SetSizer(mainSizer)
		mainSizer.Fit(self)
		mainSizer.SetSizeHints(self)
		
	def bindEvents(self):
		self.Bind(wx.EVT_BUTTON, self.onCancel, self.cancelButton)
		self.Bind(wx.EVT_COMBOBOX, self.onNetworkChange, self.networksCombo)
		self.Bind(wx.EVT_BUTTON, self.onSelect, self.selectButton)
		
	def onCancel(self, event):
		self.finalize()
		
	def onSelect(self, event):
		self.Show(False)
		tmp = NetworkJoinerEditor(self.context.mainwindow, self.context, self.context.session.hpnetwork, self.selectedNetwork)
		self.finalize()
		
	def onNetworkChange(self, event):
		self.selectedNetwork = self.networks[self.networkNames.index(event.GetString())]
		self.checkSelectButton()
		
	def checkSelectButton(self):
		if self.selectedNetwork == None:
			self.selectButton.Disable()
		else:
			self.selectButton.Enable()
	
	def finalize(self):
		self.Destroy()

class NetworkJoinerEditor(wx.Frame):
	'''
	This frame asks the user to select the network which 
	will be joined with the currently active one.
	'''
	def __init__(self, parent, context, network1, network2):
		wx.Frame.__init__(self, parent, -1, u"Network Join Editor")
		self.context = context
		self.project = self.context.session.hpproject
		self.network1 = network1
		self.network2 = network2
		self.joinNodes = [['','','']]
		self.mapping1 = []
		self.mapping2 = []
		self.warnings = []
		self.name_node_map = {}
		
		self.network1Names = [n.name for n in self.network1.nodes]
		self.network2Names = [n.name for n in self.network2.nodes]

		for node in self.network1.nodes:
			self.name_node_map[node.name]=node
		
		for node in self.network2.nodes:
			self.name_node_map[node.name]=node
		
		self.previous1 = -1
		self.previous2 = -1
		self.doLayout()
		self.bindEvents()
		self.Centre()
		self.Show()
			
	def doLayout(self):
		panel = wx.Panel(self, -1)
		
		bSizer1 = wx.BoxSizer( wx.VERTICAL )
		bSizer3 = wx.BoxSizer( wx.VERTICAL )
		bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
		bSizer4.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		bSizer5 = wx.BoxSizer( wx.VERTICAL )
		
		self.m_staticText1 = wx.StaticText( panel, wx.ID_ANY, "Network '" + self.network1.name + "'", wx.DefaultPosition, wx.DefaultSize, 0|wx.RAISED_BORDER )
		self.m_staticText1.Wrap( -1 )
		self.m_staticText1.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
		
		bSizer5.Add( self.m_staticText1, 0, wx.ALL|wx.EXPAND, 5 )
		
		self.lc1 = wx.ListCtrl( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_HRULES|wx.LC_NO_HEADER|wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES )
		self.lc1.InsertColumn(0, "")
		self.lc1.SetColumnWidth(0, 1000)
		index = 0
		for nodeName in self.network1Names:
			self.lc1.InsertStringItem(index, nodeName)
			index += 1
		
		bSizer5.Add( self.lc1, 4, wx.ALL|wx.EXPAND, 5 )
		bSizer4.Add( bSizer5, 10, wx.ALIGN_RIGHT|wx.EXPAND, 10 )
		bSizer6 = wx.BoxSizer( wx.VERTICAL )
		
		self.m_staticText2 = wx.StaticText( panel, wx.ID_ANY, "Network '" + self.network2.name + "'", wx.DefaultPosition, wx.DefaultSize, 0|wx.RAISED_BORDER )
		self.m_staticText2.Wrap( -1 )
		self.m_staticText2.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
		
		bSizer6.Add( self.m_staticText2, 0, wx.ALL|wx.EXPAND, 5 )
		
		self.lc2 = wx.ListCtrl( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_HRULES|wx.LC_NO_HEADER|wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VRULES )
		self.lc2.InsertColumn(0, "")
		self.lc2.SetColumnWidth(0, 1000)
		index = 0
		for nodeName in self.network2Names:
			self.lc2.InsertStringItem(index, nodeName)
			index += 1
			
		bSizer6.Add( self.lc2, 4, wx.ALL|wx.EXPAND, 5 )
		bSizer4.Add( bSizer6, 10, wx.EXPAND, 5 )
		bSizer4.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 )
		
		self.addMappingBtn = wx.Button( panel, wx.ID_ANY, u"Merge Selected Objects", wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer3.Add( self.addMappingBtn, 0, wx.ALIGN_CENTER|wx.ALL, 5 )
		
		bSizer1.Add( bSizer3, 4, wx.EXPAND, 5 )
		
		self.m_staticline1 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
		bSizer1.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 )
		
		bSizer17 = wx.BoxSizer( wx.VERTICAL )
		bSizer19 = wx.BoxSizer( wx.HORIZONTAL )
		bSizer19.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		
		self.m_staticText11 = wx.StaticText( panel, wx.ID_ANY, u"Merged Objects", wx.DefaultPosition, wx.DefaultSize, 0|wx.RAISED_BORDER )
		self.m_staticText11.Wrap( -1 )
		self.m_staticText11.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
		
		bSizer19.Add( self.m_staticText11, 20, wx.ALL, 5 )
		bSizer19.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		bSizer17.Add( bSizer19, 1, wx.EXPAND | wx.ALL, 5 )
		bSizer7 = wx.BoxSizer( wx.HORIZONTAL )
		
		bSizer7.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		
		self.lc3 = wx.ListCtrl( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT )
		self.lc3.InsertColumn(0, self.network1.name + " nodes")
		self.lc3.InsertColumn(1, self.network2.name + " nodes")
		self.lc3.InsertColumn(2, "Merge status")
		bSizer7.Add( self.lc3, 20, wx.ALL|wx.EXPAND, 5 )
		
		
		bSizer7.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		bSizer17.Add( bSizer7, 3, wx.EXPAND, 5 )
		bSizer18 = wx.BoxSizer( wx.HORIZONTAL )
		
		bSizer18.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		
		self.conflictBtn = wx.Button( panel, wx.ID_ANY, u"Conflicts", wx.DefaultPosition, wx.DefaultSize, 0 )
		self.conflictBtn.Disable()
		bSizer18.Add( self.conflictBtn, 0, wx.ALIGN_BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
		
		self.removeBtn = wx.Button( panel, wx.ID_ANY, u"Remove", wx.DefaultPosition, wx.DefaultSize, 0 )
		self.removeBtn.Disable()
		bSizer18.Add( self.removeBtn, 0, wx.ALIGN_BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
		
		
		bSizer18.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		bSizer17.Add( bSizer18, 1, wx.ALIGN_CENTER|wx.EXPAND, 5 )
		bSizer1.Add( bSizer17, 3, wx.EXPAND, 5 )
		
		self.m_staticline2 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
		bSizer1.Add( self.m_staticline2, 0, wx.EXPAND |wx.ALL, 5 )
		
		bSizer9 = wx.BoxSizer( wx.HORIZONTAL )
		
		
		bSizer9.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		
		self.joinBtn = wx.Button( panel, wx.ID_ANY, u"Join Networks", wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer9.Add( self.joinBtn, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
		
		self.cancelBtn = wx.Button( panel, wx.ID_ANY, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer9.Add( self.cancelBtn, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
		
		
		bSizer9.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
		bSizer1.Add( bSizer9, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 )
		self.lc3.Bind(wx.EVT_LEFT_DCLICK, self.onDClick)
		panel.SetSizer( bSizer1 )
		self.Layout()
		
	def bindEvents(self):
		self.Bind(wx.EVT_BUTTON, self.onAdd, self.addMappingBtn)
		self.Bind(wx.EVT_BUTTON, self.onRemove, self.removeBtn)
		self.Bind(wx.EVT_BUTTON, self.onShowConflicts, self.conflictBtn)
		self.Bind(wx.EVT_BUTTON, self.onCancel, self.cancelBtn)
		self.Bind(wx.EVT_BUTTON, self.onJoin, self.joinBtn)

	def onSelection(self, event):
		pass
	
	def onAdd(self, event):
		if self.lc1.GetSelectedItemCount() != 1 or self.lc2.GetSelectedItemCount() != 1:
			return
		index1 = self.lc1.GetFocusedItem()
		index2 = self.lc2.GetFocusedItem()
		if not self.__check_type(self.network1Names[index1], self.network2Names[index2]):
			return
		self.lc1.DeleteItem(index1)
		self.lc2.DeleteItem(index2)
		self.mapping1.append(self.network1Names.pop(index1))
		self.mapping2.append(self.network2Names.pop(index2))
		self.warnings.append(self.__check_diffs(self.mapping1[-1], self.mapping2[-1]))
		diffs = self.warnings[-1].__len__()
		if diffs == 0:
			diffs = "No conflicts"
		else:
			diffs = str(diffs) + " conflicts"
		itemCount = self.lc3.GetItemCount()
		self.lc3.InsertStringItem(itemCount, self.mapping1[-1])
		self.lc3.SetStringItem(itemCount, 1, self.mapping2[-1])
		self.lc3.SetStringItem(itemCount, 2, diffs)
		item = self.lc3.GetItem(itemCount)
		if self.warnings[-1].__len__() == 0:
			item.SetTextColour(wx.GREEN)
		else:
			item.SetTextColour(wx.RED)
		self.lc3.SetItem(item)
		
		self.removeBtn.Enable()
		self.conflictBtn.Enable()
		
	def onRemove(self, event):
		if self.lc3.GetSelectedItemCount() < 1:
			return
		
		while True:
			itemIndex = -1
			itemIndex = self.lc3.GetNextSelected(itemIndex)
			if itemIndex == -1:
				break
			self.network1Names.append(self.mapping1.pop(itemIndex))
			self.lc1.InsertStringItem(self.lc1.GetItemCount(), self.network1Names[-1])
			self.network2Names.append(self.mapping2.pop(itemIndex))
			self.lc2.InsertStringItem(self.lc2.GetItemCount(), self.network2Names[-1])
			self.warnings.pop(itemIndex)
			self.lc3.DeleteItem(itemIndex)
			
		if self.lc3.GetItemCount() == 0:
			self.removeBtn.Disable()
			self.conflictBtn.Disable()
	
	def onShowConflicts(self, event):
		if self.lc3.GetSelectedItemCount() != 1:
			return
		itemIndex = self.lc3.GetFocusedItem()
		self.__showConflicts(itemIndex)
		
	def onCancel(self, event):
		self.Destroy()
		
	def onJoin(self, event):
		joiner = NetworkJoiner(self.context, self.network1, self.network2, self.mapping1, self.mapping2)
		newNetworkName = self.__askForNetworkName()
		if newNetworkName != None:
			newNetwork = joiner.join(newNetworkName)
			import commands
			commands.open_network(self.context, newNetwork)
			self.Destroy()
			
	def onDClick(self, event):
		if self.lc3.GetSelectedItemCount() != 1:
			return
		self.__showConflicts(self.lc3.GetFocusedItem())
		
	def __showConflicts(self, index):
		if self.warnings[index].__len__() > 0:
			conflicts = "There are differences between node '" + self.mapping1[index] + "' and '" + self.mapping2[index] + "' in the following fields:\n"
			for field in self.warnings[index]:
				conflicts += "- " + field + "\n"
		else:
			conflicts = "There are no differences between node '" + self.mapping1[index] + "' and '" + self.mapping2[index] + "'."
		dlg = wx.MessageDialog(self, conflicts, "Conflicts between " + self.mapping1[index] + " and " + self.mapping2[index], wx.OK|wx.ICON_INFORMATION)
		dlg.ShowModal()
		dlg.Destroy()
			
	def __check_type(self, nodename1, nodename2):
		if self.name_node_map[nodename1].type_id != self.name_node_map[nodename2].type_id:
			firstName = self.context.session.dbsession.query(NodeType).filter(NodeType.id == self.name_node_map[nodename1].type_id).first().name
			secondName = self.context.session.dbsession.query(NodeType).filter(NodeType.id == self.name_node_map[nodename2].type_id).first().name
			self.context.session.dbsession.flush()
			dlg = wx.MessageDialog(self, firstName + " nodes and " + secondName + " nodes cannot be merged together.\nOnly objects of the same type can be merged.", "Error: Invalid mapping", wx.OK|wx.ICON_ERROR)
			dlg.ShowModal()
			dlg.Destroy()
			return False
		return True
	
	def __check_diffs(self, node_name1, node_name2):
		values_node1 = self.context.session.dbsession.query(NodeValue).filter(NodeValue.node_id==self.name_node_map[node_name1].id).order_by(NodeValue.attribute_id).all()
		values_node2 = self.context.session.dbsession.query(NodeValue).filter(NodeValue.node_id==self.name_node_map[node_name2].id).order_by(NodeValue.attribute_id).all()
		warnings = []
		iter1 = 0
		iter2 = 0
		while iter1 < min(values_node1.__len__(), values_node2.__len__()) and iter2 < min(values_node1.__len__(), values_node2.__len__()):
			if values_node1[iter1].attribute_id == values_node2[iter2].attribute_id:
				if str(type(values_node1[iter1].value).__name__)=='ndarray':
				    if values_node1[iter1].value.tolist()!=values_node2[iter2].value.tolist():
						warnings.append(values_node1[iter1].attribute_id)	
				else:
					if values_node1[iter1].value != values_node2[iter2].value: 
						warnings.append(values_node1[iter1].attribute_id)
				iter1+=1
				iter2+=1
			elif values_node1[iter1].attribute_id > values_node2[iter2].attribute_id:
				warnings.append(values_node2[iter2].attribute_id)
				iter2+=1
			else:
				warnings.append(values_node1[iter1].attribute_id)
				iter1+=1
		if values_node1.__len__()> iter1:
			for index in range(iter1,values_node1.__len__()):
				warnings.append(values_node1[index].attribute_id)
		elif values_node2.__len__()> iter2:
			for index in range(iter2,values_node2.__len__()):
				warnings.append(values_node2[index].attribute_id)
		
		warnings = [self.context.session.dbsession.query(NodeField).filter(NodeField.id == field).first().name for field in warnings]
		self.context.session.dbsession.flush()
		return warnings
	
	def __askForNetworkName(self):
		networkDlg = wx.TextEntryDialog(self, "What will be the name of the new network?", "New network name")
		newName = None
		while True:
			if networkDlg.ShowModal() == wx.ID_OK:
				newName = networkDlg.GetValue()
				if newName == "":
					continue
				networkDlg.Destroy()
			else:
				newName = None
			break
			
		return newName
		
class NetworkJoiner:
	'''
	This class is responsible for the actual join of the two networks
	'''
	def __init__(self, context, network1, network2, mappings1, mappings2):
		self.context = context
		self.project = self.context.session.hpproject
		self.network1 = network1
		self.network2 = network2
		self.mappings1 = mappings1
		self.mappings2 = mappings2
		
		# Translate the names of nodes into their respective ids
		for node in network1.nodes:
			if node.name in mappings1:
				self.mappings1[mappings1.index(node.name)] = node.id
		for node in network2.nodes:
			if node.name in mappings2:
				self.mappings2[mappings2.index(node.name)] = node.id

	def __isinteger(self, num):
		try:
			int(num)
			return True
		except ValueError:
			return False
			
	def __pick_unique_name(self, node):
		tokens = node.name.split("_")
		if tokens.__len__() < 3 or tokens[-2] != "copy" or self.__isinteger(tokens[-1]):
			tokens.insert(tokens.__len__(), "copy")
			tokens.insert(tokens.__len__(), "0")
		addition = 1
		while True:	
			new_name = "".join([tokens[i] + "_" for i in range(0, tokens.__len__() - 1)])
			new_name += str(int(tokens[-1]) + addition)
			if self.context.session.dbsession.query(Node).filter(Node.name == new_name).first() == None:
				break
			else:
				addition += 1

		return new_name
	
	def __copy_node_values(self, old_node, new_node):
		node_values = self.context.session.dbsession.query(NodeValue).filter(NodeValue.node_id == old_node.id).all()
		for node_value in node_values:
			self.context.session.dbsession.add(db.NodeValue(new_node.id, node_value.attribute_id, node_value.value))
		
	def join(self, new_network_name):
		net = db.Network(new_network_name, self.project)
		
		#new_nodes = {}
		id_to_nodes = {}
		# Create new nodes that correspond to the nodes of the active network
		for node in self.network1.nodes:
			#new_node = db.Node(self.__pick_unique_name(node), self.project, self.context.session.dbsession.query(NodeType).filter(NodeType.id == node.type_id).first(), None)
			#new_node.set_coord(node.x, node.y)
			#net.add_node(new_node)
			#new_nodes[node.id] = new_node
			net.add_node(node)
			id_to_nodes[node.id] = node
		
		# Create new nodes that correspond to the nodes of the network that is going to be joined
		mappings = {}
		for node in self.network2.nodes:
			if node.id not in self.mappings2:
				#new_node = db.Node(self.__pick_unique_name(node), self.project, self.context.session.dbsession.query(NodeType).filter(NodeType.id == node.type_id).first(), None)
				#new_node.set_coord(node.x, node.y)
				#net.add_node(new_node)
				#new_nodes[node.id] = new_node
				net.add_node(node)
				id_to_nodes[node.id] = node
			else:
				mappings[node.id] = self.mappings1[self.mappings2.index(node.id)]
		#self.context.session.dbsession.add(net)
		#self.context.session.dbsession.commit()
		
		'''
		for node in self.network1.nodes:
			self.__copy_node_values(node, new_nodes[node.id])
		for node in self.network2.nodes:
			if node.id not in self.mappings2:
				self.__copy_node_values(node, new_nodes[node.id])
		'''
		for link in self.network1.links:
			#new_link = db.Link(self.project, new_nodes[link.start_node_id], new_nodes[link.end_node_id], self.context.session.dbsession.query(LinkType).filter(LinkType.id == link.type_id).first())
			#net.add_link(new_link)
			net.add_link(link)
		
		for link in self.network2.links:
			#if mappings.get(link.start_node_id, -1) >= 0:
			#	start_node = new_nodes[mappings[link.start_node_id]]
			#else:
			#	start_node = new_nodes[link.start_node_id]
			#if mappings.get(link.end_node_id, -1) >= 0:
			#	end_node = new_nodes[mappings[link.end_node_id]]
			#else:
			#	end_node = new_nodes[link.end_node_id]
			#new_link = db.Link(self.project, start_node, end_node, self.context.session.dbsession.query(LinkType).filter(LinkType.id == link.type_id).first())
			#net.add_link(new_link)
			if mappings.get(link.start_node_id, -1) >= 0:
				start_node = id_to_nodes[mappings[link.start_node_id]]
				if mappings.get(link.end_node_id, -1) >= 0:
					end_node = id_to_nodes[mappings[link.end_node_id]]
				else:
					end_node = id_to_nodes[link.end_node_id]
				new_link = self.context.session.dbsession.query(Link).filter(Link.start_node_id == start_node.id).filter(Link.end_node_id == end_node.id).first()
				if new_link == None:
					new_link = db.Link(self.project, start_node, end_node, self.context.session.dbsession.query(LinkType).filter(LinkType.id == link.type_id).first())
			elif mappings.get(link.end_node_id, -1) >= 0:
				start_node = id_to_nodes[link.start_node_id]
				end_node = id_to_nodes[mappings[link.end_node_id]]
				new_link = self.context.session.dbsession.query(Link).filter(Link.start_node_id == start_node.id).filter(Link.end_node_id == end_node.id).first()
				if new_link == None:
					new_link = db.Link(self.project, start_node, end_node, self.context.session.dbsession.query(LinkType).filter(LinkType.id == link.type_id).first())
			else:
				new_link = link
			net.add_link(new_link)
				
		
		self.context.session.dbsession.add(net)
		self.context.session.dbsession.commit()
		return net